﻿using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore;
using MS.BasicData.Domain;

namespace MS.BasicData.Read.API.Interceptor
{
    public class AuditTrailInterceptor : SaveChangesInterceptor
    {
        private readonly IHttpContextAccessor _httpContextAccessor;

        public AuditTrailInterceptor(IHttpContextAccessor httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor;
        }

        public override InterceptionResult<int> SavingChanges(DbContextEventData data, InterceptionResult<int> result)
        {
            TrackChanges(data);
            return base.SavingChanges(data, result);
        }

        public override ValueTask<InterceptionResult<int>> SavingChangesAsync(DbContextEventData data, InterceptionResult<int> result, CancellationToken cancellationToken = default)
        {
            TrackChanges(data);
            return base.SavingChangesAsync(data, result, cancellationToken);
        }

        private void TrackChanges(DbContextEventData data)
        {
            ArgumentNullException.ThrowIfNull(data.Context);
            data.Context.ChangeTracker.DetectChanges();

            foreach (var entry in data.Context.ChangeTracker.Entries())
            {
                //遍历所有要操作的实体
                if (entry.Entity is IAuditable auditable)
                {
                    switch (entry.State)
                    {
                        case EntityState.Deleted:
                            UpdateAuditFields(auditable, "Remove");
                            entry.State = EntityState.Modified;
                            break;

                        case EntityState.Added:
                            UpdateAuditFields(auditable, "Create");
                            break;

                        case EntityState.Modified:
                            UpdateAuditFields(auditable, "Update");
                            break;
                    }
                }
            }
        }

        private void UpdateAuditFields(IAuditable auditable, string action)
        {
            var currentTime = DateTime.UtcNow;
            const int adminId = 888;
            const string adminName = "阿忧";
            // int adminId = Convert.ToInt32(_httpContextAccessor.HttpContext?.User.FindFirstValue("Id"));
            // string? adminName = _httpContextAccessor.HttpContext?.User.FindFirstValue("Sub");

            switch (action)
            {
                case "Remove":
                    auditable.IsDeleted = true;
                    auditable.DeleteOperatorId = adminId;
                    auditable.DeleteOperatorName = adminName;
                    auditable.DeleteDate = currentTime;
                    break;

                case "Create":
                    auditable.CreateOperatorId = adminId;
                    auditable.CreateOperatorName = adminName;
                    auditable.CreateDate = currentTime;
                    break;

                case "Update":
                    auditable.ModifyOperatorId = adminId;
                    auditable.ModifyOperatorName = adminName;
                    auditable.ModifyDate = currentTime;
                    break;
            }
        }
    }
}
